package info.liujiachen.security.test.config;

import info.liujiachen.security.test.pojo.JwtLoginAuthenticationToken;
import info.liujiachen.security.test.pojo.JwtUserDetails;
import info.liujiachen.security.test.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

public class JwtLoginAuthenticationProvider implements AuthenticationProvider {

    private JwtUserDetailsService detailsService;

    public JwtLoginAuthenticationProvider(JwtUserDetailsService detailsService) {
        this.detailsService = detailsService;
    }

    @Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {
        JwtLoginAuthenticationToken result = null;
        if (supports(auth.getClass())) {
            String username = (String) auth.getPrincipal();
            JwtUserDetails details = detailsService.getCacheUser(username);
            if (details == null) {
                details = detailsService.loadUserByUsername(username);
            }
            check(details, auth);
            detailsService.cacheUser(details);
            result = new JwtLoginAuthenticationToken(details.getUsername(), auth.getCredentials(), details.getAuthorities());
            result.setDetails(auth.getDetails());
        }
        return result;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return JwtLoginAuthenticationToken.class.isAssignableFrom(aClass);
    }

    private void check(JwtUserDetails details, Authentication auth) {
        if (!details.isAccountNonLocked()) {
            throw new LockedException("User account is locked");
        }
        if (!details.isEnabled()) {
            throw new DisabledException("User is disabled");
        }
        if (!details.isAccountNonExpired()) {
            throw new AccountExpiredException("User account has expired");
        }
        if (!details.isCredentialsNonExpired()) {
            throw new CredentialsExpiredException("User credentials have expired");
        }
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        String passwordEncoder = encoder.encode(details.getPassword());
        if (details.getPassword() == null || !encoder.matches((String) auth.getCredentials(), passwordEncoder)) {
            throw new BadCredentialsException("Bad credentials");
        }
    }

}
